<template>
  <view class="tn-progress-circle" :style="containerstyle">
    <!-- 未激活圆环/默认圆环 -->
    <canvas
      class="tn-progress-circle__progress"
      :canvas-id="id"
      :id="id"
    />
    <!-- 激活圆环 -->
    <canvas
      class="tn-progress-circle__progress"
      :canvas-id="activeId"
      :id="activeId"
    />
    <!-- 内容 -->
    <slot>
      <view v-if="showValue" class="value">{{ currentPercent }}%</view>
    </slot>
  </view>
</template>

<script lang="ts" setup>
import { circleProgressProps } from '../../../types/tn-progress'
import { ref, computed, getCurrentInstance, ComponentInternalInstance, watch, nextTick, onMounted, CSSProperties } from 'vue'
import { uuid, handleValueWithUnit } from '../../../utils'

const props = defineProps(circleProgressProps)

// 宽度
const width = computed<number>(() => {
  return uni.upx2px(props?.width ? Number(props.width) : 200)
})
// 圆环宽度
const borderWidth = computed<number>(() => {
  return uni.upx2px(props?.borderWidth ? Number(props.borderWidth) : 200)
})
// 激活时的颜色
const activeColor = computed<string>(() => {
  return props?.activeColor || '#01BEFF'
})
// 未激活时的颜色
const inactiveColor = computed<string>(() => {
  return props.inactiveColor || '#E6E6E6'
})
// 动画时间
const duration = computed<number>(() => {
  return Number(props?.duration) || 2000
})

// 容器样式
const containerstyle = computed<CSSProperties>(() => {
  let style: CSSProperties = {}
  if (width.value) {
    style.width = handleValueWithUnit(width.value, 'px')
    style.height = style.width
  }
  if (activeColor.value) style.color = activeColor.value
  return style
})

const instance = getCurrentInstance() as ComponentInternalInstance
// 容器id
const id = uuid()
const activeId = uuid()
// canvas上下文对象
let progressContext: UniApp.CanvasContext | null = null
let activeProgressContext: UniApp.CanvasContext | null = null

// 圆环开始角度
const startAngle = -90 * Math.PI / 180

// 进度信息
let currentPercent = ref<number>(0)
let prevPercent = ref<number>(0)
watch(() => props.percent, (nVal: number, oVal: number | undefined) => {
  currentPercent.value = nVal > 100 ? 100 : nVal
  prevPercent.value = !oVal || oVal < 0 ? 0 : oVal

  nextTick(() => {
    drawActiveProgress(prevPercent.value)
  })
}, {
  immediate: true
})

// 绘制progress对象
const drawProgress = () => {
  if (!progressContext) {
    progressContext = uni.createCanvasContext(id, instance)
  }
  const radius = width.value / 2
  // 设置颜色\线框
  progressContext.setLineWidth(borderWidth.value)
  progressContext.setStrokeStyle(inactiveColor.value)
  progressContext.arc(radius, radius, radius - borderWidth.value, 0, 360 * Math.PI / 180, false)
  progressContext.stroke()
  progressContext.draw()
}

// 绘制progress进度对象
const drawActiveProgress = (percent: number) => {
  if (!activeProgressContext) {
    activeProgressContext = uni.createCanvasContext(activeId, instance)
  }
  // 设置颜色\线框
  activeProgressContext.setLineCap('round')
  activeProgressContext.setLineWidth(borderWidth.value)
  activeProgressContext.setStrokeStyle(activeColor.value)
  // 计算增加百分之一的时间
  let durationTime: number = duration.value / 100
  // 计算结束圆弧的角度，360/100 * percent + start
  const endAngle = ((360 * Math.PI / 180) / 100) * percent + startAngle
  const radius = width.value / 2
  activeProgressContext.beginPath()
  activeProgressContext.arc(radius, radius, radius - borderWidth.value, startAngle, endAngle, false)
  activeProgressContext.stroke()
  activeProgressContext.draw()

  // 如果当前进度比之前的进度大则说明时增加
  if(currentPercent.value > prevPercent.value) {
    percent++
    if (percent > currentPercent.value) return
  } else {
    percent--
    if (percent < currentPercent.value) return
  }
  setTimeout(() => drawActiveProgress(percent), durationTime);
}

onMounted(() => {
  nextTick(() => {
    drawProgress()
    drawActiveProgress(0)
  })
})
</script>

<script lang="ts">
export default {
  options: {
    // 在微信小程序中将组件节点渲染为虚拟节点，更加接近Vue组件的表现(不会出现shadow节点下再去创建元素)
    virtualHost: true
  }
}
</script>

<style lang="scss" scoped>

.tn-progress-circle {
  position: relative;
  background-color: transparent;
  display: flex;
  align-items: center;
  justify-content: center;

  &__progress {
    width: 100%;
    height: 100%;
    position: absolute;
  }
}
</style>
